﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using ET199ComLib;
using COM;

namespace EncryptionServer.DogHelper
{
    public class Dog
    {
        private static Dog instance = null;
        private static ET199 et;
        private static Mutex accessDogMtx = new Mutex();
        public static string strDogCode;
        const int MIN_ASC = 32;
        const int MAX_ASC = 126;
        const int NUM_ASC = 95;

        private Dog()
        {
            //System.Windows.Forms.MessageBox.Show("初始化坚实");
            try
            {
                et = new ET199();
            }
            catch(Exception ex)
            {
                WriteLogForCheck.WriteLogFile(DateTime.Now + ":" + ex.Message);
 
            }
            //System.Windows.Forms.MessageBox.Show("初始化坚实完成");
            WriteLogForCheck.WriteLogFile(DateTime.Now + ":初始化加密狗成功，获取加密狗设备");

            int num = et.Enum();
            WriteLogForCheck.WriteLogFile(DateTime.Now + ":获取加密狗设备" +num);

            //System.Windows.Forms.MessageBox.Show("试着打开第一个USB口");
            try
            {
                WriteLogForCheck.WriteLogFile(DateTime.Now + ":打开第一个设备");
                et.Open(0);
                WriteLogForCheck.WriteLogFile(DateTime.Now + ":第一个设备打开成功");
            }
            catch (Exception)
            {
                WriteLogForCheck.WriteLogFile(DateTime.Now + ":打开第2个设备");

               // System.Windows.Forms.MessageBox.Show("打开每一个失败了，那么试个打开第二个");
                et.Open(1);
            }
            WriteLogForCheck.WriteLogFile(DateTime.Now + ":加密狗初始刷成功");
            
        }

        public static Dog GetInstance
        {
            get
            {
                if (instance == null)
                {
                    //System.Windows.Forms.MessageBox.Show("正在NEW");
                    WriteLogForCheck.WriteLogFile(DateTime.Now + ":初始化加密狗");

                    instance = new Dog();
                    //System.Windows.Forms.MessageBox.Show("初始化成功");
                }
                
                return instance;
            }
        }

        private enum ReturnCode
        {
            OK = 1,
            FindFail = -1,
            OpenFail = -2,//打开加密狗错误
            CreateDirectoryFail = -3,
            CreateFileFail = -4,
            WriteFileFial = -5,
            ReadFileFial = -6,
            Pwderr = -7,
            RunFileFail = -8
        };

        /// <summary>
        /// 获得加密狗编号,通过webService得到密文用
        /// </summary>
        /// <param name="dogCode"></param>
        /// <returns></returns>
        public int GetDogCode(out byte[] dogCode)
        {
            dogCode = null;
            WriteLogForCheck.WriteLogFile(DateTime.Now + ":寻找加密狗");


            accessDogMtx.WaitOne();
            WriteLogForCheck.WriteLogFile(DateTime.Now + ":找到加密狗");

            try
            {

                int lenth = ((sbyte[])et.ID).Length;
                dogCode = new byte[lenth];
                //Buffer.BlockCopy((sbyte[])et.ID, 0, dogCode, 0, lenth);
                //HEXStringToString(ref dogCode);
                sbyte[] id = (sbyte[])et.ID;
                HEXStringToString(ref id);
                Buffer.BlockCopy(id, 0, dogCode, 0, lenth);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                WriteLogForCheck.WriteLogFile("获取加密狗编码失败  " + DateTime.Now.ToString());
                return (int)ReturnCode.OpenFail;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;

        }

        /// <summary>
        /// 检查开发商密码
        /// </summary>
        public int CheckSuperPWD()
        {

            object objDevPinOrigin = new byte[24] 
            {
                0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,
                0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31,
                0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31
            };
            accessDogMtx.WaitOne();
            try
            {
                et.VerifyPin(ref objDevPinOrigin, ET_PIN_TYPE.ET_DEV_PIN);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.Pwderr;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;
        }
        /// <summary>
        /// 检查用户密码
        /// </summary>
        /// <returns></returns>
        private int CheckUserPWD()
        {
            accessDogMtx.WaitOne();
            object objUserPin = new byte[8]
            {
                0x38,0x37,0x36,0x35,0x34,0x33,0x32,0x31
            };
            try
            {
                et.VerifyPin(ref objUserPin, ET_PIN_TYPE.ET_USER_PIN);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.Pwderr;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;
        }

        /// <summary>
        /// 通过日期获得Web加密加密狗编号
        /// </summary>
        /// <returns></returns>
        public int GetEnWebDogCodeByData(string data, out string enwebdogcode,out string errMsg)
        {
            enwebdogcode = string.Empty;
            errMsg = string.Empty;
            object indata = Encoding.ASCII.GetBytes(data);
            object outdata = new byte[8];
            int bytesReturn;
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();

                et.Execute("3007", ref indata, data.Length, ref outdata, out bytesReturn);//通过日期得到加密狗编号密文
                string endogStr = Encoding.ASCII.GetString((byte[])outdata);
                enwebdogcode = data + endogStr;

            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                errMsg = errInfo;
                return (int)ReturnCode.RunFileFail;
            }
            return (int)ReturnCode.OK;
        }

        /// <summary>
        /// 通过日期加密加密狗编号
        /// </summary>
        /// <returns></returns>
        public string GetEnDogCode()
        {
            string enDogCode = string.Empty;
            string dtstr = new string(DateTime.Now.GetDateTimeFormats()[3].ToCharArray().Reverse().ToArray());
            dtstr = dtstr.Replace("-", "");
            object indata = Encoding.ASCII.GetBytes(dtstr);
            object outdata = new byte[16];
            int outbytes = 0;
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                et.Execute("3002", ref indata, ((byte[])indata).Length, ref outdata, out outbytes);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                WriteLogForCheck.WriteLogFile(errInfo + DateTime.Now.ToString());
            }
            enDogCode = Encoding.ASCII.GetString((byte[])outdata);
            return enDogCode;

        }

        /// <summary>
        /// 整理加密狗编号sbyte
        /// </summary>
        /// <param name="bytes"></param>
        private void HEXStringToString(ref sbyte[] bytes)
        {
            for (int i = 0; i < bytes.Length; i++)
            {
                if ((int)(bytes[i]) < MIN_ASC && (int)(bytes[i]) >= 0)
                {
                    bytes[i] = (sbyte)((int)(bytes[i]) + 33);
                }
                else if ((int)(bytes[i]) > MAX_ASC && (int)(bytes[i]) <= 220)
                {
                    bytes[i] = (sbyte)((int)(bytes[i]) - 94);
                }
                else if ((int)(bytes[i]) > 220)
                {
                    bytes[i] = (sbyte)((int)(bytes[i]) - 188);
                }
                else if ((int)(bytes[i]) <= -1 && (int)(bytes[i]) > -64)
                {
                    bytes[i] = (sbyte)((int)(bytes[i]) + 97);
                }
                else if ((int)(bytes[i]) <= -64)
                {
                    bytes[i] = (sbyte)((int)(bytes[i]) + 161);
                }
            }
        }

        /// <summary>
        /// 获得加密狗最后到期时间
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public int GetLastDate(out DateTime dt)
        {
            dt = new DateTime();
            object indata = new byte[8];
            object outdata = new byte[8];
            int bytesReturn;
            try
            {
                int devnum = et.Enum();
                if (devnum == 0)
                {
                    return (int)ReturnCode.FindFail;
                }
                et.Open(0);
                et.ChangeDir("\\");
                CheckUserPWD();
                et.Execute("3006", ref indata, 8, ref outdata, out bytesReturn);
                string lastDateStr = Encoding.ASCII.GetString((byte[])outdata);
                lastDateStr = new string(lastDateStr.ToCharArray().Reverse().ToArray());
                dt = new DateTime(Convert.ToInt32(lastDateStr.Substring(0, 4)), Convert.ToInt32(lastDateStr.Substring(4, 2)), Convert.ToInt32(lastDateStr.Substring(6, 2)));
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.RunFileFail;
            }
            return (int)ReturnCode.OK;
        }
        /// <summary>
        /// 写加密字符串文件0x2001
        /// </summary>
        /// <returns></returns>
        public int WritePwdStrFile(byte[] byFileData)
        {
            int wSize = (int)byFileData.Length;
            object indata = new byte[256];
            object outdata = new byte[1];
            int outByte = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                int byFileDataLength = byFileData.Length / 255;
                for (int i = 0; i < byFileDataLength; i++)
                {
                    ((byte[])indata)[0] = (byte)(i);
                    Buffer.BlockCopy(byFileData, i * 255, (byte[])indata, 1, 255);
                    string a = Encoding.ASCII.GetString((byte[])indata);
                    et.Execute("3005", ref indata, ((byte[])indata).Length, ref outdata, out outByte);
                }
                int mod = byFileData.Length % 255;
                if (mod != 0)
                {

                    indata = new byte[256];
                    ((byte[])indata)[0] = (byte)(byFileDataLength);
                    Buffer.BlockCopy(byFileData, byFileDataLength * 255, (byte[])indata, 1, mod);
                    string a = Encoding.ASCII.GetString((byte[])indata);
                    et.Execute("3005", ref indata, ((byte[])indata).Length, ref outdata, out outByte);
                }

            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.WriteFileFial;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;
        }

        /// <summary>
        /// 读取日期文件
        /// </summary>
        /// <returns></returns>
        public DateTime ReadDateFile()
        {
            DateTime dt = new DateTime();
            object indata = null;
            object outdata = new byte[10];
            int outbytes = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                et.Execute("3006", ref indata, 0, ref outdata, out outbytes);
                string dtstr = Encoding.ASCII.GetString((byte[])outdata);
                dt = Convert.ToDateTime(dtstr);

            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                WriteLogForCheck.WriteLogFile(errInfo + "  " + DateTime.Now.ToString());
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return dt;
        }
        /// <summary>
        /// 读取网卡mac地址文件
        /// </summary>
        /// <returns></returns>
        public string ReadNetCardMacFile()
        {
            string netCardMac = string.Empty;
            object indata = null;
            object outdata = new byte[17];
            int outbytes = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                et.Execute("3003", ref indata, 0, ref outdata, out outbytes);
                netCardMac = Encoding.ASCII.GetString((byte[])outdata);

            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                WriteLogForCheck.WriteLogFile(errInfo + "  " + DateTime.Now.ToString());
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return netCardMac;
        }
        /// <summary>
        /// 读取exe文件MD5码
        /// </summary>
        /// <returns></returns>
        public string ReadEXEMD5File()
        {
            string EXEMD5 = string.Empty;
            object indata = null;
            object outdata = new byte[32];
            int outbytes = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                et.Execute("3004", ref indata, 0, ref outdata, out outbytes);
                EXEMD5 = Encoding.ASCII.GetString((byte[])outdata);

            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                WriteLogForCheck.WriteLogFile(errInfo + "  " + DateTime.Now.ToString());
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return EXEMD5;
        }

        /// <summary>
        /// 写日期文件
        /// </summary>
        /// <param name="byFileData"></param>
        /// <returns></returns>
        public int WriteDateFile(DateTime dt)
        {
            string dtstr = dt.GetDateTimeFormats()[3];
            byte[] bytedate = Encoding.ASCII.GetBytes(dtstr);
            byte[] bytedata = new byte[256];
            bytedata[0] = 0x40;
            bytedata[1] = 0x06;
            Buffer.BlockCopy(bytedate, 0, bytedata, 2, bytedate.Length);
            object indata = bytedata;
            object outdata = new byte[1];
            int outByte = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                string a = Encoding.ASCII.GetString((byte[])indata);
                et.Execute("3001", ref indata, ((byte[])indata).Length, ref outdata, out outByte);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.WriteFileFial;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;
        }
        /// <summary>
        /// 写EXE文件 MD5码
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public int WriteEXEMD5File(byte[] bytesMD5)
        {
            byte[] bytedata = new byte[256];
            bytedata[0] = 0x40;
            bytedata[1] = 0x02;
            Buffer.BlockCopy(bytesMD5, 0, bytedata, 2, bytesMD5.Length);
            object indata = bytedata;
            object outdata = new byte[1];
            int outByte = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                string a = Encoding.ASCII.GetString((byte[])indata);
                et.Execute("3001", ref indata, ((byte[])indata).Length, ref outdata, out outByte);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.WriteFileFial;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;
        }
        /// <summary>
        /// 写网卡MAC地址  
        /// </summary>
        /// <param name="bytesMD5"></param>
        /// <returns></returns>
        public int WriteNetCardMacFile(byte[] bytesNetCardMac)
        {
            byte[] bytedata = new byte[256];
            bytedata[0] = 0x40;
            bytedata[1] = 0x03;
            Buffer.BlockCopy(bytesNetCardMac, 0, bytedata, 2, bytesNetCardMac.Length);
            object indata = bytedata;
            object outdata = new byte[1];
            int outByte = 0;
            accessDogMtx.WaitOne();
            try
            {
                int num = et.Enum();
                et.Open(0);
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                string a = Encoding.ASCII.GetString((byte[])indata);
                et.Execute("3001", ref indata, ((byte[])indata).Length, ref outdata, out outByte);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                return (int)ReturnCode.WriteFileFial;
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return (int)ReturnCode.OK;
        }

        /// <summary>
        /// 解密XY坐标
        /// </summary>
        /// <param name="xy"></param>
        /// <returns></returns>
        public string DeciperXY(string xy)
        {
            object indata = Encoding.ASCII.GetBytes(xy);
            object outdata = new byte[8];
            int outByte = 0;
            accessDogMtx.WaitOne();
            //ET199 et = new ET199();
            //int num = et.Open();
            try
            {
                try
                {
                    if (et == null)
                    {
                        et = new ET199();
                    }
                    int ret = et.Enum();
                    et.Open(0);
                }
                catch
                { }
                et.ChangeDir("\\");
                CheckSuperPWD();
                CheckUserPWD();
                string a = Encoding.ASCII.GetString((byte[])indata);
                et.Execute("3008", ref indata, ((byte[])indata).Length, ref outdata, out outByte);
            }
            catch (COMException e)
            {
                string errInfo = et.FormatErrorMessage(e.ErrorCode);
                WriteLogForCheck.WriteLogFile("解密XY出错: " + errInfo + "。  " + DateTime.Now.ToString());
            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }
            return Encoding.ASCII.GetString((byte[])outdata);
        }

        /// <summary>
        /// 获得加密狗数量
        /// </summary>
        /// <returns></returns>
        public int GetDogNum()
        {
            try
            {
                return et.Enum();
            }
            catch
            {
                return 0;
            }
        }
        public void CloseDog()
        {
            accessDogMtx.WaitOne();
            try
            {
                et.Close();
            }
            catch (Exception)
            {

            }
            finally
            {
                accessDogMtx.ReleaseMutex();
            }

        }

        /// <summary>
        /// 解密加密狗编号
        /// </summary>
        /// <param name="strFromText"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public string Decipher(string strFromText, string key)
        {
            StringBuilder result = new StringBuilder();
            char[] random = key.ToCharArray();
            char[] from_text = strFromText.ToCharArray();
            char[] buf1 = new char[strFromText.Length];
            int offset;
            int str_len = 1;
            int i;
            int ch;

            str_len = from_text.Length;
            try
            {
                for (i = 0; i < str_len; i++)
                {
                    ch = (int)from_text[i];
                    if (ch >= MIN_ASC && ch <= MAX_ASC)
                    {
                        ch = ch - MIN_ASC;
                        offset = (NUM_ASC + 1) * random[i];
                        ch = (ch - offset) % NUM_ASC;
                        if (ch < 0)
                        {
                            ch = ch + NUM_ASC;
                        }
                        ch = ch + MIN_ASC;
                        buf1[i] = (char)ch;
                    }
                    else
                    {
                        buf1[i] = from_text[i];
                    }
                }
                foreach (var item in buf1)
                {
                    result.Append(item);
                }
            }
            catch (Exception)
            {
                result = new StringBuilder("");
            }

            return result.ToString();
        } 


    }
}
